/* bitfield.c is part of VIP program
 * Written by J. Salvador Arias, 2010
 *      CONICET, INSUE, Instituto Miguel Lillo,
 *      Miguel Lillo 205, S.M. de Tucuman (4000)
 *      Tucuman, Argentina
 *      e-mail: jsalarias@csnat.unt.edu.ar
 *
 * VIP is a free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation and
 * Creative Commons.
 *
 * This file and the VIP program is distributed in the hope
 * that it will be useful, but WITHOUT ANY WARRANTY; without
 * even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * To view a copy of this license, visit
 * http://creativecommons.org/licenses/GPL/2.0/
 * or send a letter to
 * Creative Commons, 171 Second Street, Suite 300,
 * San Francisco, California, 94105, USA.
 */

#include "bitfield.h"

static SCOUNTER numBits [65536];
static SCOUNTER maxNumFields = 0;

static void AddBits (BITFIELD act);

void AddBits (BITFIELD act) {
 SCOUNTER count, i;
 BITFIELD bit, trgt;

 count = numBits [act] + 1;
 for (i = 0; i < BITS_ON_FIELD; ++ i) {
   bit = 1 << i;
   trgt = bit | act;
   if (numBits [trgt] == 0) {
     numBits [trgt] = count;
     AddBits (trgt);
   }
 }
}

void StartBitFields (SCOUNTER bits) {
 SCOUNTER i;
 static SFLAG bitCountReady = FALSE;

 if (bits == 0) {
   EndBitFields ();
   return;
 }
 maxNumFields = (bits / BITS_ON_FIELD) + 1;
 maxFieldSize = sizeof (BITFIELD) * maxNumFields;
 if (bitCountReady == FALSE) {
   for (i = 0; i < 65536; ++ i)
     numBits [i] = 0;
   AddBits (0);
 }
 bitCountReady = TRUE;
}

void EndBitFields () {
 maxNumFields = 0;
 maxFieldSize = 0;
}

BITFIELD* CreateBitField () {
 BITFIELD* nu;
 SCOUNTER i;

 nu = (BITFIELD*) g_slice_alloc (maxFieldSize);
 for (i = 0; i < maxNumFields; ++ i)
   nu [i] = 0;
 return nu;
}

void ResetBitField (BITFIELD* a) {
 SCOUNTER i;
 for (i = 0; i < maxNumFields; ++ i)
   a [i] = 0;
}

void PutBitOn (BITFIELD* a, SCOUNTER bit) {
 SCOUNTER actField;
 SCOUNTER actBit;

 actField = bit / BITS_ON_FIELD;
 actBit = bit % BITS_ON_FIELD;
 a [actField] |= (1 << actBit);
}

SFLAG IsBitOn (BITFIELD* a, SCOUNTER bit) {
 SCOUNTER actField;
 SCOUNTER actBit;

 actField = bit / BITS_ON_FIELD;
 actBit = 1 << (bit % BITS_ON_FIELD);
 return (a [actField] & actBit) ? TRUE : FALSE;
}

void CopyBitField (BITFIELD* dest, BITFIELD* src) {
 SCOUNTER i;
 for (i = 0; i < maxNumFields; ++ i)
   dest [i] = src [i];
}

SFLAG BitFieldAnd (BITFIELD* a1, BITFIELD* a2) {
 SCOUNTER i;
 for (i = 0; i < maxNumFields; ++ i) {
   if (a1 [i] & a2 [i]) return TRUE;
 }
 return FALSE;
}

SFLAG BitFieldEqual (BITFIELD* a1, BITFIELD* a2) {
 SCOUNTER i;
 for (i = 0; i < maxNumFields; ++ i) {
   if (a1 [i] != a2 [i]) return FALSE;
 }
 return TRUE;
}

void BitFieldORsum (BITFIELD* dest, BITFIELD* src) {
 SCOUNTER i;
 for (i = 0; i < maxNumFields; ++ i)
   dest [i] |= src [i];
}

void BitFieldANDsum (BITFIELD* dest, BITFIELD* src) {
 SCOUNTER i;
 for (i = 0; i < maxNumFields; ++ i)
   dest [i] &= src [i];
}

void BitFieldRemove (BITFIELD* dest, BITFIELD* toRemov) {
 SCOUNTER i;
 for (i = 0; i < maxNumFields; ++ i)
   dest [i] &= ~ toRemov [i];
}

SCOUNTER CountBits (BITFIELD* a) {
 SCOUNTER num;
 SCOUNTER i;

 num = 0;
 for (i = 0; i < maxNumFields; ++ i)
   num += numBits [a [i]];
 return num;
}

SCOUNTER BitFieldCommon (BITFIELD* a, BITFIELD* b) {
 SCOUNTER num;
 SCOUNTER i;

 num = 0;
 for (i = 0; i < maxNumFields; ++ i)
   num += numBits [a [i] & b [i]];
 return num;
}

void BitFieldAddNotRemoved (BITFIELD* dest, BITFIELD* src, BITFIELD* toRemov) {
 SCOUNTER i;
 for (i = 0; i < maxNumFields; ++ i)
   dest [i] |= (src [i] & (~ toRemov [i]));
}
